//
//  ViewController.m
//  JomooProject
//
//  Created by 张键 on 2022/2/11.
//

#import "JMIOTViewController.h"
#import "JMCommonUtils.h"

#import "JMIotUtils.h"
#import "UIButton+JMImagePosition.h"
#import "Definition.h"
#import <IMSApiClient/IMSApiClient.h>
#import "FFLoading.h"

@interface JMIOTViewController () <IMSThingObserver> {
}

@property(nonatomic, strong) NSTimer *timer;
@property(nonatomic, assign) BOOL isPaused;

#pragma mark -

//@property(strong, nonatomic) dispatch_block_t delayBlock;

@end

@implementation JMIOTViewController

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    self.navigationController.navigationBar.hidden = true;
    [JMCommonUtils resetRootViewFrameWillAppear];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    self.navigationController.navigationBar.hidden = false;
    [JMCommonUtils resetRootViewFrameWillDisappear];
}

/**
 - (id)init {
 NSString *nibName = NSStringFromClass(self.class);
 NSBundle *bundle = [JD274SModuleBundle bundle];

 self = [super initWithNibName:nibName bundle:bundle];
 if (self) {
 }

 return self;
 }
 */

- (void)InitUI {
}

#pragma mark - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// 遍历
- (void)allViews:(UIView *)rootView indent:(NSInteger)indent {
    // NSLog(@"[%2d] %@", (int)indent, rootView);
    indent++;
    if ([rootView isKindOfClass:UIScrollView.class]) {
        if (@available(iOS 11.0, *)) {
            // UIScrollView *scrv = (UIScrollView *)rootView;
            // scrv.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
            // scrv.showsVerticalScrollIndicator = false;
            // scrv.showsHorizontalScrollIndicator = false;
        }
    }
    for (UIView *aView in [rootView subviews]) {
        [self allViews:aView indent:indent];
    }
}

// 保证所有touch事件button的highlighted属性为NO,即可去除高亮效果
- (void)preventFlicker:(UIButton *)button {
    button.highlighted = NO;
}

#pragma mark - 创建/取消延时方法

/**
 //创建延时方法
 - (void)performDelayedTask:(NSDictionary *)items {
 @weakify(self);
 _delayBlock = dispatch_block_create(DISPATCH_BLOCK_BARRIER, ^{
 @strongify(self);
 [self delayUpdateState:items];
 self->_delayBlock = nil;
 });
 dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC));
 dispatch_after(delayTime, dispatch_get_main_queue(), _delayBlock);
 }

 //取消延时方法
 - (void)cancelDelayedTask {
 if (_delayBlock) {
 dispatch_block_cancel(_delayBlock);
 _delayBlock = nil;
 NSLog(@"Delayed task canceled.");
 }
 }

 //延迟刷新
 - (void)delayUpdateState:(NSDictionary *)items {
 }
 */

- (void)performDelayedUpdateTask:(NSDictionary *)items {
    static dispatch_block_t block_delay = nil;

    // 取消延时方法
    if (block_delay) {
        dispatch_block_cancel(block_delay);
        block_delay = nil;
        NSLog(@"Delayed task canceled.");
    }

    @weakify(self);
    block_delay = dispatch_block_create(DISPATCH_BLOCK_BARRIER, ^{
      @strongify(self);
      if (!self) {
          return;
      }
      [self updateState:items];
      block_delay = nil;
    });
    dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC));
    dispatch_after(delayTime, dispatch_get_main_queue(), block_delay);
}

#pragma mark - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// 检查网络是否可用
- (bool)checkNetworkAvailable {
    if (![JMCommonUtils isNetworkReachable]) {
        NSDictionary *info = @{
            @"message" : @"网络异常，请检查网络连接",
            NSLocalizedDescriptionKey : @"网络异常，请检查网络连接",
        };
        NSError *err = [NSError errorWithDomain:@"" code:0 userInfo:info];
        [JMCommonUtils ShowToastByContent:err.localizedDescription afterDelay:2.0 actionEnabled:true withBlock:nil];
        return false;
    }
    return true;
}

#pragma mark - toast相关内容

- (bool)isShowToast:(UIButton *)btn {
    NSString *str = @"";

    if (btn.alpha != 1.0) {
        if (str.length > 0) {
            [JMCommonUtils ShowToastByContent:str afterDelay:2.0 actionEnabled:true withBlock:nil];
        }
        return true;
    } else {
        return false;
    }
}

#pragma mark - 按钮点击,可复用

//
- (IBAction)btnDown:(UIButton *)btn {
    // 按钮之间要间隔 1s 才能点击
    {
        static bool bool_clicked = false;
        // 判断是否间隔 1s
        if (bool_clicked) {
            return;
        }
        bool_clicked = true;
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
          bool_clicked = false;
        });
    }

    // 判断是否要弹出提示
    if ([self isShowToast:btn]) {
        return;
    }

    int flag = 0;
    if (btn.selected) {
        flag = 0;
    } else {
        flag = 1;
    }

    [self updateBtnState:btn];
}

// 更新按钮状态
- (void)updateBtnState:(UIButton *)btn {
}

#pragma mark - 可复用

- (void)viewDidLoad {
    [super viewDidLoad];

    [self InitUI];

    [self resetALL];
    [self configIOT];
    [self getPropertiesFull:true completionHandler:nil];
    [self getStatus];
    [self getEvents];
    [self addNotifications];

    _mdic_state = [[NSMutableDictionary alloc] init];
}

- (void)dealloc {
    NSLog(@"dealloc");
    [self destroyAll];
}

- (IBAction)back:(id)sender {
    [self destroyAll];
    [self.navigationController popViewControllerAnimated:true];
}

#pragma mark - 初始化所有数据

- (void)resetALL {
}

#pragma mark - 销毁所有数据

- (void)destroyAll {
    [self destroyIOT];

    //[self cancelDelayedTask];

    [self removeNotifications];

    [self destroyTimer];

    [NSObject cancelPreviousPerformRequestsWithTarget:self];
}

#pragma mark - 刷新所有状态

- (BOOL)isDataUpdated:(NSDictionary *)items completion:(void (^)(bool isEqual, NSDictionary *completionDic))block {
    // 判断数据有更新
    NSMutableDictionary *nItems = [NSMutableDictionary dictionary];
    [nItems setDictionary:_mdic_state];
    [nItems addEntriesFromDictionary:items];

    NSMutableDictionary *mItems = [NSMutableDictionary dictionary];
    for (NSString *key in nItems.allKeys) {
        mItems[key] = nItems[key][@"value"];
    }

    NSMutableDictionary *mdic = [NSMutableDictionary dictionary];
    for (NSString *key in _mdic_state.allKeys) {
        mdic[key] = _mdic_state[key][@"value"];
    }
    BOOL isEqual = [mItems isEqual:mdic];
    if (!isEqual) {
        //[mdic_state setDictionary:nItems];
    }
    if (block) {
        block(isEqual, nItems);
    }
    return isEqual;
}

// 刷新状态
- (void)updateState:(NSDictionary *)items {
    NSLog(@"updateState");

    /**
     //判断数据有更新
     {
     NSMutableDictionary *mItems = [NSMutableDictionary dictionary];
     for (NSString *key in items.allKeys) {
     mItems[key] = items[key][@"value"];
     }

     NSMutableDictionary *mdic = [NSMutableDictionary dictionary];
     for (NSString *key in _mdic_state.allKeys) {
     mdic[key] = _mdic_state[key][@"value"];
     }
     BOOL isEqual = [mItems isEqual:mdic];
     if (isEqual) {
     return;
     }
     }
     */
}

#pragma mark - IOT

- (void)destroyIOT {
    if (!self.shouldNotDestroyWhenExit) {
        // 销毁
        [kIMSThingManager destroyThing:self.thingShell];
    }
    [self.thingShell unregisterThingObserver:self];
    self.thingShell = nil;

    /**
     关闭本地通信能力
     */
    //[kIMSThingManager stopLocalAcceleration];
    /**
     清理 SDK 中缓存的用户数据，特别是对设备的进行控制的授权信息，在用户注销账号时记得调用
     */
    //[kIMSThingManager clearLocalCache];
}

- (void)configIOT {
    [self destroyIOT];

    /**
     1）需要手动开启
     2）需要注意账号切换的的时候的缓存清除
     3）当然，如果并不需要的时候可以关闭
     开启本地通信能力，需要在操作物时提前调用，可以多次调用，但必须至少调用过一次
     */
    //[kIMSThingManager startLocalAcceleration];

    self.thingShell = [kIMSThingManager buildThing:self.iotId];
    //_iotId为云端给设备颁发的唯一标识
    // IMSThing *thingShell = [kIMSThingManager buildThing:@"a1L3iU6fpeU" deviceName:@"jd053_sh_cmf_001" iotId:IIotID];
    // 当不再需要使用时，请记得销毁，如下所示：
    //[kIMSThingManager destroyThing:thingShell];
    // 如果需要获取设备的 iotId
    // NSString * iotId = [thingShell iotId];

    [self.thingShell registerThingObserver:self];
    // 注册设备状态、属性变化、以及事件触发的观察者。
    //  具体参见 `IMSThingObserver`，并请注意注册的Observer的生命周期
    //  SDK只会Weak reference其实例,请开发者自己保证Observer的生命周期。
    //  不需要监听时，请注销[_thingShell unregisterThingObserver:self];

    /*
     IMSThingProfile * Profile = [thingShell getThingProfile];
     //其中物的三要素 保存在 IMSThingProfile 中。
     _thingProperties = [[_thingShell getThingProfile] allPropertiesOfModel];
     _thingEvents =  [[_thingShell getThingProfile] allEventsOfModel];
     _thingServices =  [[_thingShell getThingProfile] allServicesOfModel];
     // 注意，此处拿到的 properties，events，services 是物的模型中的物的三要素。
     // 具体请参见 IoT-TSL 规范
     */
}

- (void)getStatus {
    [[self.thingShell getThingActions] getStatus:^(IMSThingActionsResponse *_Nullable response) {
      NSDictionary *properties = [response.dataObject valueForKey:@"data"];
      NSLog(@"properties = %@", properties);
      // 格式如下：
      /* {
       "status":1 //
       "time":1232341455
       }
       说明：status表示设备生命周期，目前有以下几个状态，
       0:未激活；1：上线；3：离线；8：禁用；time表示当前状态的开始时间；
       */
    }];
}

- (void)getEvents {
    [[self.thingShell getThingActions] getEvents:^(IMSThingActionsResponse *_Nullable response) {
      NSArray *arr = [response.dataObject valueForKey:@"data"];
      // NSLog(@"properties = %@", properties);
      for (NSDictionary *properties in arr) {
          [self onEventHappen:self.iotId params:properties];
      }
    }];
}

- (void)getPropertiesFull {
    [self getPropertiesFull:nil];
}

- (void)getPropertiesFull:(void (^)(BOOL success, NSDictionary *items, NSError *responseError))block {
    [self getPropertiesFull:YES completionHandler:block];
}

- (void)getPropertiesFull:(bool)isUpdate completionHandler:(void (^)(BOOL success, NSDictionary *items, NSError *responseError))block {
    [self getPropertiesFullV1:isUpdate completionHandler:block];
}

// 获取属性的方法(新)
- (void)getPropertiesFullV1:(bool)isUpdate completionHandler:(void (^)(BOOL success, NSDictionary *items, NSError *responseError))block {
    if (![JMCommonUtils isNetworkReachable]) {
        NSDictionary *info = @{
            @"message" : @"网络异常，请检查网络连接",
            NSLocalizedDescriptionKey : @"网络异常，请检查网络连接",
        };
        NSError *err = [NSError errorWithDomain:@"" code:0 userInfo:info];
        if (block) {
            block(false, nil, err);
        }
        [JMCommonUtils ShowToastByContent:err.localizedDescription afterDelay:2.0 actionEnabled:true withBlock:nil];
        return;
    }

    @weakify(self);
    [JMIotUtils getDevicePropertiesWithIotId:self.iotId
                           completionHandler:^(NSError *error, id data) {
                             NSDictionary *properties = (NSDictionary *)data;
                             // NSLog(@"properties = %@", properties);
                             dispatch_async(dispatch_get_main_queue(), ^{
                               bool responseSuccess = false;
                               if (!error) {
                                   responseSuccess = true;
                               }
                               if (block) {
                                   block(responseSuccess, properties, error);
                               }
                               if (!responseSuccess || error) {
                                   NSLog(@"response.success = %d", responseSuccess);
                                   NSLog(@"response.responseError = %@", error);

                                   IMSResponse *httpResponse = error.userInfo[@"rawData"];
                                   if (httpResponse.code == 401 || httpResponse.code == 1005) {
                                       [FFLoading showAutomicHiddenHudText:@"您的账号在另外一台手机登录,请重新登录"];
#define ACCOUNT_FORCE_LOGOUT @"AcountForceLogout"
                                       [[NSNotificationCenter defaultCenter] postNotificationName:ACCOUNT_FORCE_LOGOUT
                                                                                           object:nil];
                                   }
                               } else {
                                   @strongify(self);
                                   if (self.isInterrupting) {
                                       return;
                                   }
                                   if (isUpdate) {
                                       [self isDataUpdated:properties
                                                completion:^(bool isEqual, NSDictionary *completionDic) {
                                                  @strongify(self);
                                                  if (!isEqual) {
                                                      [self->_mdic_state setDictionary:completionDic];
                                                      [self updateState:completionDic];
                                                  }
                                                }];
                                   }
                               }
                             });
                           }];
}

// 获取属性的方法(旧)
- (void)getPropertiesFullOriginal:(bool)isUpdate completionHandler:(void (^)(BOOL success, NSDictionary *items, NSError *responseError))block {
    if (![JMCommonUtils isNetworkReachable]) {
        NSDictionary *info = @{
            @"message" : @"网络异常，请检查网络连接",
            NSLocalizedDescriptionKey : @"网络异常，请检查网络连接",
        };
        NSError *err = [NSError errorWithDomain:@"" code:0 userInfo:info];
        if (block) {
            block(false, nil, err);
        }
        [JMCommonUtils ShowToastByContent:err.localizedDescription afterDelay:2.0 actionEnabled:true withBlock:nil];
        return;
    }

    @weakify(self);
    /**
     获取物的所有属性的当前值
     extraData 附加控制属性  key:@"IotPerformanceId" 性能测试
     key:@"Channel", value: ChannelPolicyCloud ChannelPolicyLocal   ChannelPolicyLocalPrefer
     handler 结果回调函数，请参考 `IMSThingActionsResponseHandler`
     */
    NSDictionary *extraData = @{@"Channel" : @(ChannelPolicyLocalPrefer)};
    [[self.thingShell getThingActions] getPropertiesV1:extraData
                                       responseHandler:^(IMSThingActionsResponse *_Nullable response) {
                                         NSDictionary *properties = [response.dataObject valueForKey:@"data"];
                                         // NSLog(@"properties = %@", properties);
                                         dispatch_async(dispatch_get_main_queue(), ^{
                                           if (block) {
                                               block(response.success, properties, response.responseError);
                                           }
                                           if (!response.success || response.responseError) {
                                               NSLog(@"response.success = %d", response.success);
                                               NSLog(@"response.responseError = %@", response.responseError);

                                               IMSResponse *httpResponse = response.responseError.userInfo[@"rawData"];
                                               if (httpResponse.code == 401 || httpResponse.code == 1005) {
                                                   [FFLoading showAutomicHiddenHudText:@"您的账号在另外一台手机登录,请重新登录"];
#define ACCOUNT_FORCE_LOGOUT @"AcountForceLogout"
                                                   [[NSNotificationCenter defaultCenter] postNotificationName:ACCOUNT_FORCE_LOGOUT
                                                                                                       object:nil];
                                               }
                                           } else {
                                               @strongify(self);
                                               if (self.isInterrupting) {
                                                   return;
                                               }
                                               if (isUpdate) {
                                                   [self isDataUpdated:properties
                                                            completion:^(bool isEqual, NSDictionary *completionDic) {
                                                              @strongify(self);
                                                              if (!isEqual) {
                                                                  [self->_mdic_state setDictionary:completionDic];
                                                                  [self updateState:completionDic];
                                                              }
                                                            }];
                                               }
                                           }
                                         });
                                       }];
}

- (void)setProperties:(NSDictionary *)items completionHandler:(void (^)(BOOL success, id dataObject, NSError *responseError))block {
    [self setPropertiesV1:items completionHandler:block];
}

// 设置属性的方法(新)
- (void)setPropertiesV1:(NSDictionary *)items completionHandler:(void (^)(BOOL success, id dataObject, NSError *responseError))block {
    if (![JMCommonUtils isNetworkReachable]) {
        NSDictionary *info = @{
            @"message" : @"网络异常，请检查网络连接",
            NSLocalizedDescriptionKey : @"网络异常，请检查网络连接",
        };
        NSError *err = [NSError errorWithDomain:@"" code:0 userInfo:info];
        if (block) {
            block(false, nil, err);
        }
        [JMCommonUtils ShowToastByContent:err.localizedDescription afterDelay:2.0 actionEnabled:true withBlock:nil];
        return;
    }

    // 备份原来的属性字典
    NSMutableDictionary *mdic_original = [NSMutableDictionary dictionaryWithDictionary:self.mdic_state];
    NSMutableDictionary *mdic_new = [NSMutableDictionary dictionaryWithDictionary:self.mdic_state];
    for (NSString *key in items.allKeys) {
        mdic_new[key] = @{@"value" : items[key], @"time" : @(0)};
    }
    [self.mdic_state setDictionary:mdic_new];

    @weakify(self);
    [JMIotUtils setDevicePropertiesWithIotId:self.iotId
                                      params:items
                           completionHandler:^(NSError *error, id data) {
                             dispatch_async(dispatch_get_main_queue(), ^{
                               @strongify(self);
                               bool responseSuccess = false;
                               if (!error) {
                                   responseSuccess = true;
                               }
                               // 如果发送指令失败就把属性字典还原回来
                               if (!responseSuccess || error) {
                                   [self.mdic_state setDictionary:mdic_original];
                               }
                               if (block) {
                                   block(responseSuccess, data, error);
                               }
                               if (!responseSuccess || error) {
                                   NSLog(@"response.success = %d", responseSuccess);
                                   NSLog(@"response.responseError = %@", error);

                                   IMSResponse *httpResponse = error.userInfo[@"rawData"];
                                   if (httpResponse.code == 401 || httpResponse.code == 1005) {
                                       [FFLoading showAutomicHiddenHudText:@"您的账号在另外一台手机登录,请重新登录"];
#define ACCOUNT_FORCE_LOGOUT @"AcountForceLogout"
                                       [[NSNotificationCenter defaultCenter] postNotificationName:ACCOUNT_FORCE_LOGOUT
                                                                                           object:nil];
                                   }
                               }
                             });
                           }];
}

// 设置属性的方法(旧)
- (void)setPropertiesOriginal:(NSDictionary *)items completionHandler:(void (^)(BOOL success, id dataObject, NSError *responseError))block {
    if (![JMCommonUtils isNetworkReachable]) {
        NSDictionary *info = @{
            @"message" : @"网络异常，请检查网络连接",
            NSLocalizedDescriptionKey : @"网络异常，请检查网络连接",
        };
        NSError *err = [NSError errorWithDomain:@"" code:0 userInfo:info];
        if (block) {
            block(false, nil, err);
        }
        [JMCommonUtils ShowToastByContent:err.localizedDescription afterDelay:2.0 actionEnabled:true withBlock:nil];
        return;
    }

    // 备份原来的属性字典
    NSMutableDictionary *mdic_original = [NSMutableDictionary dictionaryWithDictionary:self.mdic_state];
    NSMutableDictionary *mdic_new = [NSMutableDictionary dictionaryWithDictionary:self.mdic_state];
    for (NSString *key in items.allKeys) {
        mdic_new[key] = @{@"value" : items[key], @"time" : @(0)};
    }
    [self.mdic_state setDictionary:mdic_new];

    @weakify(self);
    /**
     设置物的属性值，可以同时设置一个或者多个属性
     params 属性 key-value 对， 格式如{"items":{"power":"on", temperature:30}}
     extraData 附加控制属性
     key:@"IotPerformanceId" 性能测试
     key:@"Channel", value: ChannelPolicyCloud ChannelPolicyLocal   ChannelPolicyLocalPrefer
     key:@"QosLevel", value: Qos_CON Qos_NON
     key:@"NeedRsp", value:TRUE FALSE
     key:@"Flag", 用于commonservice flag参数
     handler 结果回调函数，请参考 `IMSThingActionsResponseHandler`
     */
    NSDictionary *properties = @{@"items" : items};
    NSDictionary *extraData = @{@"Channel" : @(ChannelPolicyLocalPrefer), @"QosLevel" : @"Qos_CON", @"NeedRsp" : @(YES)};
    [[self.thingShell getThingActions] setPropertiesV1:properties
                                             extraData:extraData
                                       responseHandler:^(IMSThingActionsResponse *_Nullable response) {
                                         dispatch_async(dispatch_get_main_queue(), ^{
                                           @strongify(self);
                                           // 如果发送指令失败就把属性字典还原回来
                                           if (!response.success || response.responseError) {
                                               [self.mdic_state setDictionary:mdic_original];
                                           }
                                           if (block) {
                                               block(response.success, response.dataObject, response.responseError);
                                           }
                                           if (!response.success || response.responseError) {
                                               NSLog(@"response.success = %d", response.success);
                                               NSLog(@"response.responseError = %@", response.responseError);

                                               IMSResponse *httpResponse = response.responseError.userInfo[@"rawData"];
                                               if (httpResponse.code == 401 || httpResponse.code == 1005) {
                                                   [FFLoading showAutomicHiddenHudText:@"您的账号在另外一台手机登录,请重新登录"];
#define ACCOUNT_FORCE_LOGOUT @"AcountForceLogout"
                                                   [[NSNotificationCenter defaultCenter] postNotificationName:ACCOUNT_FORCE_LOGOUT
                                                                                                       object:nil];
                                               }
                                           }
                                         });
                                       }];
}

- (void)setProperties:(NSDictionary *)items getPropertiesFull:(void (^)(BOOL success, id dataObject, NSError *responseError))block {
    if (![JMCommonUtils isNetworkReachable]) {
        NSDictionary *info = @{
            @"message" : @"网络异常，请检查网络连接",
            NSLocalizedDescriptionKey : @"网络异常，请检查网络连接",
        };
        NSError *err = [NSError errorWithDomain:@"" code:0 userInfo:info];
        if (block) {
            block(false, nil, err);
        }
        [JMCommonUtils ShowToastByContent:err.localizedDescription afterDelay:2.0 actionEnabled:true withBlock:nil];
        return;
    }

    @weakify(self);
    [self setProperties:items
        completionHandler:^(BOOL success, id dataObject, NSError *responseError) {
          dispatch_async(dispatch_get_main_queue(), ^{
            @strongify(self);
            if (!success || responseError) {
                if (block) {
                    block(success, dataObject, responseError);
                }
            } else {
                [self getPropertiesFull:^(BOOL success, id dataObject, NSError *responseError) {
                  dispatch_async(dispatch_get_main_queue(), ^{
                    if (block) {
                        block(success, dataObject, responseError);
                    }
                  });
                }];
            }
          });
        }];
}

- (void)setProperties:(NSDictionary *)items interrupt:(NSTimeInterval)duration completionHandler:(void (^)(BOOL success, id dataObject, NSError *responseError))block {
    [self setProperties:items completionHandler:block];
    [self executeInterrupt:duration];
}

// 中断操作
- (void)executeInterrupt:(NSTimeInterval)duration {
    _isInterrupting = true;
    static dispatch_block_t block_delay = nil;

    // 取消延时方法
    if (block_delay) {
        dispatch_block_cancel(block_delay);
        block_delay = nil;
        NSLog(@"Delayed task canceled.");
    }

    @weakify(self);
    block_delay = dispatch_block_create(DISPATCH_BLOCK_BARRIER, ^{
      @strongify(self);
      if (!self) {
          return;
      }
      self->_isInterrupting = false;
      [self getPropertiesFull];
      block_delay = nil;
    });
    dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC));
    dispatch_after(delayTime, dispatch_get_main_queue(), block_delay);
}

#pragma mark - IMSThingObserver

/**
 物的状态变更回调，如上线，离线等
 @param iotId 物的 iotId
 @param params 描述具体状态
 */
- (void)onStatusChange:(NSString *)iotId params:(NSDictionary *)params {
    NSLog(@"onStatusChange = %@", params);
    // 格式如下：
    /* {
     "status":1 //
     "time":1232341455
     }
     说明：status表示设备生命周期，目前有以下几个状态，
     0:未激活；1：上线；3：离线；8：禁用；time表示当前状态的开始时间；
     */
    if ([params[@"status"][@"value"] intValue] != 1) {
        [self destroyAll];

        [self.navigationController popToRootViewControllerAnimated:true];
    }
}

/**
 物有事件触发，如提示，告警等

 @param iotId 物的 iotId
 @param params 描述具体事件
 */
- (void)onEventHappen:(NSString *)iotId params:(NSDictionary *)params {
    NSLog(@"onEventHappen = %@", params);
    if (self.isInterrupting) {
        return;
    }
}

/**
 物的属性发生变化

 @param iotId 物的 iotId
 @param params 描述属性内容
 */
- (void)onPropertyChange:(NSString *)iotId params:(NSDictionary *)params {
    // NSLog(@"onPropertyChange = %@", params);
    if (self.isInterrupting) {
        return;
    }
    @weakify(self);
    [self isDataUpdated:params[@"items"]
             completion:^(bool isEqual, NSDictionary *completionDic) {
               @strongify(self);
               if (!isEqual) {
                   [self->_mdic_state setDictionary:completionDic];
                   [self updateState:completionDic];
               }
             }];
}

/**
 设备被解绑通知
 @param iotId 物的 iotId
 @param params 描述属性内容
 */
- (void)onDeviceUnbind:(NSString *)iotId params:(NSDictionary *)params {
    NSLog(@"onDeviceUnbind = %@", params);
    if (self.unbindCallBack) {
        self.unbindCallBack(iotId, params);
    }
    [self destroyAll];

    [self.navigationController popToRootViewControllerAnimated:true];
}

/**
 设备WIFI状态通知
 @param iotId 物的 iotId
 @param params 描述当前设备的WIFI状态  @{@"status":value of DeviceWifiStatusType}
 */
- (void)onDeviceWifiStatus:(NSString *)iotId params:(NSDictionary *)params {
    NSLog(@"onDeviceWifiStatus = %@", params);
}

/**
 通告本地连接状态变化，未连接《-》已连接
 @param state 连接状态，参见 `IMSLocalConnectionState`
 */
- (void)onLocalConnectionStateChange:(IMSLocalConnectionState)state {
    NSLog(@"IMSLocalConnectionState = %d", (int)state);
}

#pragma mark - NSNotificationCenter defaultCenter

- (void)addNotifications {
    [self removeNotifications];

    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    [center addObserver:self selector:@selector(notifyEvent:) name:@"ALITHING_EVENT_NOTIFY" object:nil];
}

- (void)removeNotifications {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)notifyEvent:(NSNotification *)notification {
    // notify 消息
    NSDictionary *value = [notification.object objectForKey:@"value"];
    if (value) {
        NSString *operation = [value objectForKey:@"operation"];
        if (operation && [operation isEqual:@"Unbind"]) {
            NSString *notification_iotId = [value objectForKey:@"iotId"];
            if (notification_iotId && [notification_iotId isEqualToString:self.iotId]) {
                if (self.unbindCallBack) {
                    self.unbindCallBack(self.iotId, notification.object);
                }
                [self destroyAll];

                [self.navigationController popToRootViewControllerAnimated:true];
            }
        }
    }
}

#pragma mark - Public Methods

- (void)startTimer {
    if (self.timer) {
        [self destroyTimer];
    }

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
      self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0
                                                    target:self
                                                  selector:@selector(timerFired:)
                                                  userInfo:nil
                                                   repeats:YES];
      [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
      self.isPaused = NO;
    });
}

- (void)pauseTimer {
    [self.timer setFireDate:[NSDate distantFuture]];
    self.isPaused = YES;
}

- (void)resumeTimer {
    if (self.timer && self.isPaused) {
        [self.timer setFireDate:[NSDate date]];
        self.isPaused = NO;
    }
}

- (void)destroyTimer {
    if (self.timer) {
        [self.timer invalidate];
        self.timer = nil;
    }
    self.isPaused = NO;
}

- (BOOL)isRunning {
    return (self.timer != nil && !self.isPaused);
}

#pragma mark - Private Methods

- (void)timerFired:(NSTimer *)timer {
    @weakify(self);
    dispatch_block_t block = ^{
      @strongify(self);
      if (!self) {
          return;
      }
      if (self->_isInterrupting == false) {
          [self getPropertiesFull];
      }
    };
    if ([NSThread isMainThread]) {
        block();
    } else {
        dispatch_async(dispatch_get_main_queue(), ^{
          block();
        });
    }

    // NSLog(@"Timer fired at: %@", [NSDate date]);
}

@end
